using System;
using System.Collections.Generic;
using System.Text;
using Tiago.Data;
using Nihonaid.Properties;
using Nihonaid.classes.scheduler;

namespace Nihonaid.classes
{
    /// <summary>
    /// Represents the item learning queue
    /// </summary>
    partial class LearningQueue
    {
        public enum LearningScheduler
        {
            PimsleurScheduler = 0,
            LeitnerScheduler = 1
        }

        /// <summary>
        /// Fetches the next question and answer pair (the learning item row)
        /// </summary>
        /// <returns>Learning item row that the user will answer to, null if no item present</returns>
        public LearningItem GetNextItem()
        {
            // If today's item treshold was exceeded then return null
            if (Configuration.todays_items <= 0)
                return null;
            else
            {
                // If there are items in the review queue, present these first
                if (GetReviewItemsLeft() > 0)
                {
                    this.last_fetched_review = true;
                    return (LearningItem)this.review_queue[0];
                }
                else
                    // Otherwise return an item in the learning queue, if available
                    if (GetLearningItemsLeft() > 0)
                    {
                        this.last_fetched_review = false;
                        return (LearningItem)this.learning_queue[0];
                    }
                    else
                        return null;
            }
        }

        /// <summary>
        /// Updates the current item in the database
        /// </summary>
        /// <param name="answer_type">The answer type (Correct,Wrong)</param>
        public void UpdateCurrentItem(LearningItem.AnswerType answer_type)
        {
            LearningItem current_item;
            
            // If the last fetched item was from the review queue then remove it from there
            if (this.last_fetched_review)
            {
                current_item = this.review_queue[0];
                this.review_queue.Remove(current_item);
            }
            else // If it was from the learning queue, then remove it from there
            {
                current_item = this.learning_queue[0];
                this.learning_queue.Remove(current_item);
            }

            // Update the current item according to the given answer
            switch(answer_type)
            {
                // If the user answered correctly
                case LearningItem.AnswerType.Correct:
                    current_item.CorrectAnswers++;
                    current_item.CorrectStreak++;
                    current_item.NextRepetitionDate = this.scheduler.GetNextDate(current_item.CorrectStreak);
                    current_item.LastRepetitionDate = DateTime.Now;
                    break;
                // If the user didn't know the answer or answered it incorrectly
                case LearningItem.AnswerType.Wrong:
                    current_item.WrongAnswers++;
                    current_item.CorrectStreak = 0;
                    if (current_item.CorrectAnswers > 0)
                        current_item.NextRepetitionDate = this.scheduler.GetNextDate(current_item.CorrectStreak);
                    current_item.LastRepetitionDate = DateTime.Now;
                    break;
            }
              
            UpdateLearningItemDatabase(current_item);

            // If the item was never answered correctly, then put it in the learning queue
            if (current_item.CorrectAnswers == 0)
            {
                this.learning_queue.Add(current_item);
                this.learning_queue.Sort();
            }
            else // Otherwise put it in the review queue
            {
                if(current_item.CorrectAnswers == 1)
                    Configuration.todays_items--;
                this.review_queue.Add(current_item);
                this.review_queue.Sort();
            }
        }

        /// <summary>
        /// Returns the percentage of learned hiragana
        /// </summary>
        /// <param name="type">The type of learning item to count</param>
        /// <returns>Percentage of learned hiragana (0-100)</returns>
        public int LearningItemProgress(LearningItem.QuestionType type)
        {
            double learned = 0;
            double total = 0;
            double progress = 0;

            // Returns the overall progress
            if (type == LearningItem.QuestionType.EveryType)
            {
                total += CountLearningItemTotal(LearningItem.QuestionType.HiraganaReading);
                total += CountLearningItemTotal(LearningItem.QuestionType.KanaWordMeaning);
                total += CountLearningItemTotal(LearningItem.QuestionType.KanjiMeaning);
                total += CountLearningItemTotal(LearningItem.QuestionType.KanjiWordKana);
                total += CountLearningItemTotal(LearningItem.QuestionType.KanjiWordMeaning);
                total += CountLearningItemTotal(LearningItem.QuestionType.KatakanaReading);

                learned += CountLearningItemLearned(LearningItem.QuestionType.HiraganaReading);
                learned += CountLearningItemLearned(LearningItem.QuestionType.KanaWordMeaning);
                learned += CountLearningItemLearned(LearningItem.QuestionType.KanjiMeaning);
                learned += CountLearningItemLearned(LearningItem.QuestionType.KanjiWordKana);
                learned += CountLearningItemLearned(LearningItem.QuestionType.KanjiWordMeaning);
                learned += CountLearningItemLearned(LearningItem.QuestionType.KatakanaReading);

                progress = (learned / total) * 100;
            }
            else // Returns the progress for a specific type of learning item
            {
                learned = (double)CountLearningItemLearned(type);
                total = (double)CountLearningItemTotal(type);
                progress = (learned / total) * 100;
            }

            if (double.IsNaN(progress))
                return 0;
            return Convert.ToInt32(progress);
        }

        /// <summary>
        /// Sets the scheduler according to the stored settings
        /// </summary>
        public void SetSchedulerFromSettings()
        {
            switch (Configuration.scheduler)
            {
                case 0:
                    this.scheduler = new PimsleurScheduler();
                    break;
                case 1:
                    this.scheduler = new LeitnerScheduler();
                    break;
            }
        }

        /// <summary>
        /// Resets all the performance and scheduler data in the database
        /// </summary>
        public void ResetLearningData()
        {
            Configuration.milestone1 = 0;
            Configuration.milestone2 = 48;
            Configuration.milestone3 = 69;
            Configuration.milestone4 = 96;
            Configuration.milestone5 = 104;
            Configuration.milestone6 = 236;
            Configuration.milestone7 = 336;
            Configuration.milestone8 = 2277;
            Configuration.Save();

            string updates = "correct_streak = 0, correct_answers = 0, wrong_answers = 0, next_repetition_date = '" + DateTime.Now + "', last_repetition_date = '" + DateTime.Now + "'";
            this.db.Update("LearningItems", updates);
            InitializeQueues();
        }
    }
}
